测试 ChannelHandler

    我们来编写一个简单的 ByteToMessageDecoder 实现,有足够的数据可以读取时将产生固定大小的包,如果没有足够的数据可以读取,则会等待下一个数据块并再次检查是否可以产生一个完整包。

    如图所示,它可能会占用一个以上的“event”以获取足够的字节产生一个数据包,并将它传递到 ChannelPipeline 中的下一个 ChannelHandler,

    Figure 10.2 Decoding via FixedLengthFrameDecoder

    实现如下:

    1. 继承 ByteToMessageDecoder 用来处理入站的字节并将他们解码为消息
    2. 指定产出的帧的长度
    3. 检查是否有足够的字节用于读到下个帧
    4. 从 ByteBuf 读取新帧
    5. 添加帧到解码好的消息 List

    下面是单元测试的例子,使用 EmbeddedChannel

    Listing 10.2 Test the FixedLengthFrameDecoder

    1. 新建 ByteBuf 并用字节填充它
    2. 新增 EmbeddedChannel 并添加 FixedLengthFrameDecoder 用于测试
    3. 写数据到 EmbeddedChannel
    4. 标记 channel 已经完成
    5. 读产生的消息并且校验

    如上面代码,testFramesDecoded() 方法想测试一个 ByteBuf,这个ByteBuf 包含9个可读字节,被解码成包含了3个可读字节的 ByteBuf。你可能注意到,它写入9字节到通道是通过调用 writeInbound() 方法,之后再执行 finish() 来将 EmbeddedChannel 标记为已完成,最后调用readInbound() 方法来获取 EmbeddedChannel 中的数据,直到没有可读字节。testFramesDecoded2() 方法采取同样的方式,但有一个区别就是入站ByteBuf分两步写的,当调用 writeInbound(input.readBytes(2)) 后返回 false 时,FixedLengthFrameDecoder 值会产生输出,至少有3个字节是可读,testFramesDecoded2() 测试的工作相当于testFramesDecoded()。

    Testing outbound messages

    测试的处理出站消息类似于我们刚才看到的一切。这个例子将使用的实现MessageToMessageEncoder:AbsIntegerEncoder。

    • 当收到 flush() 它将从 ByteBuf 读取4字节整数并给每个执行Math.abs()。
    • 每个整数接着写入 ChannelHandlerPipeline

    图10.3显示了逻辑。

    Figure 10.3 Encoding via AbsIntegerEncoder

    示例如下:

    Listing 10.3 AbsIntegerEncoder

    1. 检查是否有足够的字节用于编码
    2. 读取下一个输入 ByteBuf 产出的 int 值,并计算绝对值
    3. 写 int 到编码的消息 List

    在前面的示例中,我们将使用 EmbeddedChannel 测试代码。清单10.4

    Listing 10.4 Test the AbsIntegerEncoder

    1. 用 标记
    2. 新建 ByteBuf 并写入负整数
    3. 新建 EmbeddedChannel 并安装 AbsIntegerEncoder 来测试
    4. 写 ByteBuf 并预测 readOutbound() 产生的数据
    5. 读取产生到的消息,检查负值已经编码为绝对值